﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Configuration;
using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;

namespace WindowService
{ /// <summary>  
    /// 有关HTTP请求的辅助类  
    /// </summary>  
    public class HttpWebResponseUtility  
    {  
        private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";  
        /// <summary>  
        /// 创建GET方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <returns></returns>  
        public static string CreateGetHttpResponse(string url, int? timeout, Encoding encode, string userAgent, CookieCollection cookies)
        {
            Log.WriteLog("HttpWebResponseUtility GetHttp URL:" + url + " timeout:" + timeout, LogType.Trace);
            HttpWebRequest.DefaultWebProxy = null;
            if (string.IsNullOrEmpty(url))  
            {  
                throw new ArgumentNullException("url");  
            }
            if (!ToggleAllowUnsafeHeaderParsing(true))
            {
                Log.WriteLog("HttpWebResponseUtility can't setting ToggleAllowUnsafeHeaderParsing true", LogType.Error);
            }
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;  
            request.Method = "GET";
            request.UserAgent = DefaultUserAgent;
            request.UseDefaultCredentials = false;
            ServicePointManager.DefaultConnectionLimit = 500;
            if (!string.IsNullOrEmpty(userAgent))  
            {  
                request.UserAgent = userAgent;  
            }  
            if (timeout.HasValue)  
            {  
                request.Timeout = timeout.Value;  
            }  
            if (cookies != null)  
            {  
                request.CookieContainer = new CookieContainer();  
                request.CookieContainer.Add(cookies);
            }
            Guid guid = Guid.NewGuid();
            string uuid = guid.ToString();
            Log.WriteLog("HTTPClient Req ID:" + uuid + " URL:" + url + " Method:" + request.Method, LogType.Info);
            string resStr = null;
            HttpWebResponse response = null;
            try
            {
                response = request.GetResponse() as HttpWebResponse;
                StreamReader reader = new StreamReader(response.GetResponseStream(), encode);
                resStr = reader.ReadToEnd();
            }
            catch (Exception e)
            {
                Log.WriteLog("HTTPClient Res ID:" + uuid + " Message:" + e.Message, LogType.Error);
                return resStr;
            }
            finally
            {
                if(response != null) response.Close();
            }
            Log.WriteLog("HTTPClient Res ID:" + uuid + " Message:" + resStr, LogType.Info);
            return resStr;
            //return request.GetResponse() as HttpWebResponse;  
        }  
        /// <summary>  
        /// 创建POST方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <returns></returns>  
        public static string CreatePostHttpResponse(string url,IDictionary<string,string> parameters,int? timeout, string userAgent,Encoding requestEncoding,CookieCollection cookies)
        {
            Log.WriteLog("HttpWebResponseUtility PostHttp URL:" + url + " timeout:" + timeout, LogType.Trace);
            HttpWebRequest.DefaultWebProxy = null;
            
            if (string.IsNullOrEmpty(url))  
            {  
                throw new ArgumentNullException("url");  
            }  
            if(requestEncoding==null)  
            {  
                throw new ArgumentNullException("requestEncoding");  
            }
            if (!ToggleAllowUnsafeHeaderParsing(true))
            {
                Log.WriteLog("HttpWebResponseUtility can't setting ToggleAllowUnsafeHeaderParsing true", LogType.Error);
            }
            HttpWebRequest request=null;  
            //如果是发送HTTPS请求  
            if(url.StartsWith("https",StringComparison.OrdinalIgnoreCase))  
            {  
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);  
                request = WebRequest.Create(url) as HttpWebRequest;  
                request.ProtocolVersion=HttpVersion.Version10;  
            }  
            else 
            {  
                request = WebRequest.Create(url) as HttpWebRequest;  
            }
            request.Proxy = null;
            request.UseDefaultCredentials = false;
            request.KeepAlive = true;
            request.Method = "POST";  
            request.ContentType = "application/x-www-form-urlencoded";
            request.ServicePoint.Expect100Continue = false;
            ServicePointManager.DefaultConnectionLimit = 500;
            request.ReadWriteTimeout = 3000;
            Guid guid = Guid.NewGuid();
            string uuid = guid.ToString();
              
            if (!string.IsNullOrEmpty(userAgent))  
            {  
                request.UserAgent = userAgent;  
            }  
            else 
            {  
                request.UserAgent = DefaultUserAgent;  
            }  
 
            if (timeout.HasValue)  
            {  
                request.Timeout = timeout.Value;  
            }  
            if (cookies != null)  
            {  
                request.CookieContainer = new CookieContainer();  
                request.CookieContainer.Add(cookies);  
            }  
            //如果需要POST数据  
            if(!(parameters==null||parameters.Count==0))  
            {  
                StringBuilder buffer = new StringBuilder();  
                int i = 0;  
                foreach (string key in parameters.Keys)  
                {  
                    if (i > 0)  
                    {  
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);  
                    }  
                    else 
                    {  
                        buffer.AppendFormat("{0}={1}", key, parameters[key]);  
                    }  
                    i++;  
                }

                Log.WriteLog("HTTPClient Req ID:" + uuid + " URL:" + url + " Method:" + request.Method + " ContentType:" + request.ContentType + " Parameters:" + buffer.ToString(), LogType.Info);
                byte[] data = requestEncoding.GetBytes(buffer.ToString());
                Stream stream = null;
                try
                {
                    stream = request.GetRequestStream();
                    stream.Write(data, 0, data.Length);
                }
                catch (Exception e)
                {
                    Log.WriteLog("HTTPClient Res ID:" + uuid + " Message:" + e.Message, LogType.Error);
                    return null;
                }
                finally
                {
                    if (stream != null) stream.Close();
                }
            }
            string resStr = null;
            HttpWebResponse response = null;
            try
            {
                response = request.GetResponse() as HttpWebResponse;
                if (response.StatusCode == HttpStatusCode.RequestTimeout)
                {
                    Thread.Sleep(1000);
                    return null;
                }
                StreamReader reader = new StreamReader(response.GetResponseStream(), requestEncoding);
                resStr = reader.ReadToEnd();
            }
            catch (Exception e)
            {
                Log.WriteLog("HTTPClient Res ID:" + uuid + " Message:" + e.Message, LogType.Error);
            }
            finally
            {
                if(request != null) request.Abort();
                if(response != null) response.Close();
            }
            Log.WriteLog("HTTPClient Res ID:" + uuid + " Message:" + resStr, LogType.Info);
            return resStr;
            //return request.GetResponse() as HttpWebResponse;  
        }
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)  
        {  
            return true; //总是接受  
        }
        // Enable/disable useUnsafeHeaderParsing.
        public static bool ToggleAllowUnsafeHeaderParsing(bool enable)
        {
            //Get the assembly that contains the internal class
            Assembly assembly = Assembly.GetAssembly(typeof(SettingsSection));
            if (assembly != null)
            {
                //Use the assembly in order to get the internal type for the internal class
                Type settingsSectionType = assembly.GetType("System.Net.Configuration.SettingsSectionInternal");
                if (settingsSectionType != null)
                {
                    //Use the internal static property to get an instance of the internal settings class.
                    //If the static instance isn't created already invoking the property will create it for us.
                    object anInstance = settingsSectionType.InvokeMember("Section",
                    BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });
                    if (anInstance != null)
                    {
                        //Locate the private bool field that tells the framework if unsafe header parsing is allowed
                        FieldInfo aUseUnsafeHeaderParsing = settingsSectionType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
                        if (aUseUnsafeHeaderParsing != null)
                        {
                            aUseUnsafeHeaderParsing.SetValue(anInstance, enable);
                            return true;
                        }

                    }
                }
            }
            return false;
        }
    } 
}
